"""
  Sweet Soup is a patched version of Beautiful Soup,
  that returns Dummy Tag objects where Beautiful Soup
  would return None.

  authors:
  - Jure Vrscaj <jure.vrscaj@gmail.com>
  - Leonard Richardson (http://www.crummy.com/software/BeautifulSoup/)

  TODO:
  - [done] patch tag.__getitem__
"""


from BeautifulSoup import *


class SweetList(list):
    def __getitem__(self, key):
        try:
            return super(SweetList, self).__getitem__(key)
        except IndexError:
            return DummyTag(SweetSoup(), u"dummy_%s" % key)
        
    
class SweetTag(Tag):
    """ Returns DummyTag insted of None.
    """
    def __call__(self, *args, **kwargs):
        result = self.findAll(*args, **kwargs)
        return SweetList(result)

    def __getitem__(self, key):
        return self._getAttrMap().get(key, u"")
        
    def __getattr__(self, tag):
        #print "Getattr %s.%s" % (self.__class__, tag)
        if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3:
            result = self.find(tag[:-3])
        elif tag.find('__') != 0:
            result = self.find(tag)
        else:
            raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
        if result is None:
            result = DummyTag(SweetSoup(), tag)    
        elif result.__class__ == Tag:
            result.__class__ = SweetTag
        return result

class DummyTag(SweetTag):
    def __nonzero__(self):
        return False
    def __getattr__(self, tag):
        #print "Getattr %s.%s" % (self.__class__, tag)        
        if tag.startswith("__"):
            raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)            
        return self.__class__(SweetSoup(), tag)
    
    
class SweetSoup(SweetTag, BeautifulSoup):
    """ Like BeautifulSoup, but:
        - does not return None if no Tag found when accessing attributes.
        - instead returns a SweetTag instance.
    """
    
    def __getattr__(self, methodName):
        #print "__getattr__ called on %s.%s" % (self.__class__, methodName)

        if methodName.startswith('start_') or methodName.startswith('end_') \
               or methodName.startswith('do_'):
            return SGMLParser.__getattr__(self, methodName)
        elif not methodName.startswith('__'):
            result = SweetTag.__getattr__(self, methodName)
            return result
        else:
            raise AttributeError


if __name__ == '__main__':
    html = """
    <div>Foo.
      <a href="http://example.com">
        Bar.
        <b>
          Bold.
        </b>
      </a>
      <a>Baz.</a>
    </div>
    """
    
    soup = SweetSoup(html)
    soup2 = BeautifulSoup(html)
    
    try:
        soup2.div.img["href"]
    except Exception, e:
        print "BeautifulSoup.__getattr__:", e
    
    print "SweetSoup.__getattr__:", soup.div.div.div.__class__
    print "SweetSoup.__call__:",  soup.div("a").__class__
    print "SweetSoup.__getitem__:",  soup.div.img["href"].__class__
    
